// import { ElMessage, ElMessageBox } from "element-plus";
import BpmnModeler from "bpmn-js/lib/Modeler";
import DefaultEmptyXML from "./plugins/defaultEmpty";
// 翻译方法
import customTranslate from "./plugins/translate/customTranslate";
import translationsCN from "./plugins/translate/zh";
// 模拟流转流程
import tokenSimulation from "bpmn-js-token-simulation";
// 标签解析 Moddle
import camundaModdleDescriptor from "./plugins/descriptor/camundaDescriptor.json";
import activitiModdleDescriptor from "./plugins/descriptor/activitiDescriptor.json";
import flowableModdleDescriptor from "./plugins/descriptor/flowableDescriptor.json";
// 标签解析 Extension
import camundaModdleExtension from "./plugins/extension-moddle/camunda";
import activitiModdleExtension from "./plugins/extension-moddle/activiti";
import flowableModdleExtension from "./plugins/extension-moddle/flowable";
// import { XmlNode, XmlNodeType, parseXmlString } from "steady-xml";
import { Button, Tooltip } from "antd";
import { Icon } from "@/components/Icon";
import { useEffect, useMemo, useState } from "react";
import { useMessage } from "@/hooks/web/useMessage";
import "./ProcessDesigner.less";

const DesignerPropsDefault = {
	translations: {},
	moddleExtension: {},
	onlyCustomizeAddi: false,
	onlyCustomizeModdle: false,
	simulation: true,
	keyboard: true,
	prefix: "camunda",
	events: ["element.click"],
	headerButtonSize: "small", //  ['default', 'medium', 'small', 'mini']
	headerButtonType: "primary" // ['default', 'primary', 'success', 'warning', 'danger', 'info']
};

let bpmnModeler: any = null;
export default function ProcessDesigner(props: any) {
	// fix React18 "defaultProps" problem
	props = Object.assign({}, { ...DesignerPropsDefault, ...props });

	const { createMessage } = useMessage();

	// const bpmnCanvas = useRef();
	// const refFile = ref()
	function emit(key: string) {
		//   [
		//   'destroy',
		//   'init-finished',
		//   'save',
		//   'commandStack-changed',
		//   'input',
		//   'change',
		//   'canvas-viewbox-changed',
		//   // eventName.name
		//   'element-click'
		// ]
		console.log("emit", key);
	}

	// provide('configGlobal', props)
	// let bpmnModeler: any = null;
	const [defaultZoom, setDefaultZoom] = useState(1);
	// const previewModelVisible = ref(false)
	// const simulationStatus = ref(false);
	// const previewResult = ref('')
	// const previewType = ref('xml')
	const [recoverable, setRecoverable] = useState(false);
	const [revocable, setRevocable] = useState(false);
	const additionalModules = useMemo(() => {
		const Modules: any[] = [];
		// 仅保留用户自定义扩展模块
		if (props.onlyCustomizeAddi) {
			if (Object.prototype.toString.call(props.additionalModel) == "[object Array]") {
				return props.additionalModel || [];
			}
			return [props.additionalModel];
		}

		// 插入用户自定义扩展模块
		if (Object.prototype.toString.call(props.additionalModel) == "[object Array]") {
			Modules.push(...(props.additionalModel as any[]));
		} else {
			props.additionalModel && Modules.push(props.additionalModel);
		}

		// 翻译模块
		const TranslateModule = {
			translate: ["value", customTranslate(props.translations || translationsCN)]
		};

		Modules.push(TranslateModule);

		// 模拟流转模块
		if (props.simulation) {
			Modules.push(tokenSimulation);
		}

		// 根据需要的流程类型设置扩展元素构建模块
		// if (this.prefix === "bpmn") {
		//   Modules.push(bpmnModdleExtension);
		// }
		if (props.prefix === "camunda") {
			Modules.push(camundaModdleExtension);
		}
		if (props.prefix === "flowable") {
			Modules.push(flowableModdleExtension);
		}
		if (props.prefix === "activiti") {
			Modules.push(activitiModdleExtension);
		}

		return Modules;
	}, [props.onlyCustomizeAddi, props.additionalModel, props.simulation, props.prefix]);
	const moddleExtensions = useMemo(() => {
		const Extensions: any = {};
		// 仅使用用户自定义模块
		if (props.onlyCustomizeModdle) {
			return props.moddleExtension || null;
		}

		// 插入用户自定义模块
		if (props.moddleExtension) {
			for (let key in props.moddleExtension) {
				Extensions[key] = props.moddleExtension[key];
			}
		}

		// 根据需要的 "流程类型" 设置 对应的解析文件
		if (props.prefix === "activiti") {
			Extensions.activiti = activitiModdleDescriptor;
		}
		if (props.prefix === "flowable") {
			Extensions.flowable = flowableModdleDescriptor;
		}
		if (props.prefix === "camunda") {
			Extensions.camunda = camundaModdleDescriptor;
		}
		return Extensions;
	}, [props.onlyCustomizeModdle, props.moddleExtension, props.prefix]);

	const initBpmnModeler = () => {
		if (bpmnModeler) return;
		let data = document.getElementById("bpmnCanvas");

		bpmnModeler = new BpmnModeler({
			container: data,
			keyboard: props.keyboard ? { bindTo: document } : null,
			additionalModules: additionalModules,
			moddleExtensions: moddleExtensions,
			i18n: {
				translate: ["value", customTranslate(props.translations || translationsCN)]
			}
		});

		// bpmnModeler.createDiagram()
		// emit("init-finished", bpmnModeler);
		props.initFinished && props.initFinished(bpmnModeler);
		initModelListeners();
	};

	const initModelListeners = () => {
		const EventBus = bpmnModeler.get("eventBus");
		// 注册需要的监听事件, 将. 替换为 - , 避免解析异常
		// props.events.forEach((event: any) => {
		// 	EventBus.on(event, function (eventObj: any) {
		// 		// let eventName = event.replace(/\./g, "-");
		// 		// eventName.name = eventName
		// 		// let element = eventObj ? eventObj.element : null;
		// 		// emit("element-click", element, eventObj);
		// 		// props.elementClick && props.elementClick(element, eventObj);
		// 		// emit(eventName, element, eventObj)
		// 	});
		// });
		// 监听图形改变返回xml
		EventBus.on("commandStack.changed", async event => {
			try {
				// recoverable.value = bpmnModeler.get("commandStack").canRedo();
				// revocable.value = bpmnModeler.get("commandStack").canUndo();
				setRecoverable(bpmnModeler.get("commandStack").canRedo());
				setRevocable(bpmnModeler.get("commandStack").canUndo());
				let { xml } = await bpmnModeler.saveXML({ format: true });
				emit("commandStack-changed", event);
				emit("input", xml);
				emit("change", xml);
			} catch (e: any) {
				console.error(`[Process Designer Warn]: ${e.message || e}`);
			}
		});
		// 监听视图缩放变化
		bpmnModeler.on("canvas.viewbox.changed", ({ viewbox }) => {
			emit("canvas-viewbox-changed", { viewbox });
			// const { scale } = viewbox;
			// defaultZoom = Math.floor(scale * 100) / 100;
		});
	};
	/* 创建新的流程图 */
	const createNewDiagram = async xml => {
		// 将字符串转换成图显示出来
		let newId = props.processId || `Process_${new Date().getTime()}`;
		let newName = props.processName || `业务流程_${new Date().getTime()}`;
		let xmlString = xml || DefaultEmptyXML(newId, newName, props.prefix);
		try {
			let { warnings } = await bpmnModeler.importXML(xmlString);
			if (warnings && warnings.length) {
				warnings.forEach(warn => console.warn(warn));
			}
		} catch (e: any) {
			console.error(`[Process Designer Warn]: ${e.message || e}`);
		}
	};

	// // 下载流程图到本地
	// const downloadProcess = async (type) => {
	//   try {
	//     // 按需要类型创建文件并下载
	//     if (type === 'xml' || type === 'bpmn') {
	//       const { err, xml } = await bpmnModeler.saveXML()
	//       // 读取异常时抛出异常
	//       if (err) {
	//         console.error(`[Process Designer Warn ]: ${err.message || err}`)
	//       }
	//       let { href, filename } = setEncoded(type.toUpperCase(), xml)
	//       downloadFunc(href, filename)
	//     } else {
	//       const { err, svg } = await bpmnModeler.saveSVG()
	//       // 读取异常时抛出异常
	//       if (err) {
	//         return console.error(err)
	//       }
	//       let { href, filename } = setEncoded('SVG', svg)
	//       downloadFunc(href, filename)
	//     }
	//   } catch (e: any) {
	//     console.error(`[Process Designer Warn ]: ${e.message || e}`)
	//   }
	//   // 文件下载方法
	//   function downloadFunc(href, filename) {
	//     if (href && filename) {
	//       let a = document.createElement('a')
	//       a.download = filename //指定下载的文件名
	//       a.href = href //  URL对象
	//       a.click() // 模拟点击
	//       URL.revokeObjectURL(a.href) // 释放URL 对象
	//     }
	//   }
	// }

	// 根据所需类型进行转码并返回下载地址
	// const setEncoded = (type, data) => {
	// 	const filename = "diagram";
	// 	const encodedData = encodeURIComponent(data);
	// 	return {
	// 		filename: `${filename}.${type}`,
	// 		href: `data:application/${type === "svg" ? "text/xml" : "bpmn20-xml"};charset=UTF-8,${encodedData}`,
	// 		data: data
	// 	};
	// };

	// 加载本地文件
	// const importLocalFile = () => {
	//   const file = refFile.value.files[0]
	//   const reader = new FileReader()
	//   reader.readAsText(file)
	//   reader.onload = function () {
	//     let xmlStr = this.result
	//     createNewDiagram(xmlStr)
	//   }
	// }
	/* ------------------------------------------------ refs methods ------------------------------------------------------ */
	// const downloadProcessAsXml = () => {
	//   downloadProcess('xml')
	// }
	// const downloadProcessAsBpmn = () => {
	//   downloadProcess('bpmn')
	// }
	// const downloadProcessAsSvg = () => {
	//   downloadProcess('svg')
	// }
	// const processSimulation = () => {
	//   simulationStatus.value = !simulationStatus.value
	//   props.simulation && bpmnModeler.get('toggleMode', 'strict').toggleMode()
	// }
	const processRedo = () => {
		bpmnModeler.get("commandStack").redo();
	};
	const processUndo = () => {
		bpmnModeler.get("commandStack").undo();
	};
	const processZoomIn = () => {
		let zoomStep = 0.1;
		let newZoom = Math.floor(defaultZoom * 100 + zoomStep * 100) / 100;
		if (newZoom > 4) {
			throw new Error("[Process Designer Warn ]: The zoom ratio cannot be greater than 4");
		}
		// defaultZoom.value = newZoom
		setDefaultZoom(newZoom);
		bpmnModeler.get("canvas").zoom(newZoom);
	};
	const processZoomOut = () => {
		let zoomStep = 0.1;
		let newZoom = Math.floor(defaultZoom * 100 - zoomStep * 100) / 100;
		if (newZoom < 0.2) {
			throw new Error("[Process Designer Warn ]: The zoom ratio cannot be less than 0.2");
		}
		// defaultZoom.value = newZoom
		setDefaultZoom(newZoom);
		bpmnModeler.get("canvas").zoom(newZoom);
	};
	const processReZoom = () => {
		// defaultZoom.value = 1
		setDefaultZoom(1);
		bpmnModeler.get("canvas").zoom("fit-viewport", "auto");
	};
	const processRestart = () => {
		// recoverable.value = false
		// revocable.value = false
		setRecoverable(false);
		setRevocable(false);
		createNewDiagram(null);
	};
	// const elementsAlign = (align) => {
	//   const Align = bpmnModeler.get('alignElements')
	//   const Selection = bpmnModeler.get('selection')
	//   const SelectedElements = Selection.get()
	//   if (!SelectedElements || SelectedElements.length <= 1) {
	//     ElMessage.warning('请按住 Shift 键选择多个元素对齐')
	//     // alert('请按住 Ctrl 键选择多个元素对齐
	//     return
	//   }
	//   ElMessageBox.confirm('自动对齐可能造成图形变形，是否继续？', '警告', {
	//     confirmButtonText: '确定',
	//     cancelButtonText: '取消',
	//     type: 'warning'
	//   }).then(() => {
	//     Align.trigger(SelectedElements, align)
	//   })
	// }
	/*-----------------------------    方法结束     ---------------------------------*/
	// const previewProcessXML = () => {
	//   bpmnModeler.saveXML({ format: true }).then(({ xml }) => {
	//     previewResult.value = xml
	//     previewType.value = 'xml'
	//     previewModelVisible.value = true
	//   })
	// }
	// const previewProcessJson = () => {
	//   bpmnModeler.saveXML({ format: true }).then(({ xml }) => {
	//     const rootNodes = new XmlNode(XmlNodeType.Root, parseXmlString(xml))
	//     previewResult.value = rootNodes.parent?.toJSON() as unknown as string
	//     previewType.value = 'json'
	//     previewModelVisible.value = true
	//   })
	// }
	/* ------------------------------------------------ 芋道源码 methods ------------------------------------------------------ */
	const processSave = async () => {
		const { err, xml } = await bpmnModeler.saveXML();
		// 读取异常时抛出异常
		if (err) {
			createMessage.error("保存模型失败，请重试！");
			return;
		}
		// 触发 save 事件
		props.save && props.save(xml);
	};

	/** Effect */

	useEffect(() => {
		initBpmnModeler();
		createNewDiagram(props.value);
		return () => {
			if (bpmnModeler) bpmnModeler.destroy();
			emit("destroy", bpmnModeler);
			bpmnModeler = null;
		};
	}, []);

	return (
		<div className="my-process-designer">
			<div className="my-process-designer__header" style={{ zIndex: 999, display: "table-row-group" }}>
				{/* <slot name="control-header"></slot> */}
				<div className="designerPanel">
					<div className="designerPanel-buttonGroup">
						<Tooltip title="撤销">
							<Button icon={<Icon icon="ep:refresh-left" />} onClick={processUndo} disabled={!revocable} />
						</Tooltip>
						<Tooltip title="恢复">
							<Button icon={<Icon icon="ep:refresh-right" />} onClick={processRedo} disabled={!recoverable} />
						</Tooltip>
						<Tooltip title="重新绘制">
							<Button icon={<Icon icon="ep:refresh" />} onClick={processRestart} />
						</Tooltip>
					</div>
					<div className="designerPanel-buttonGroup">
						<Tooltip title="缩小视图">
							<Button icon={<Icon icon="ep:zoom-out" />} onClick={processZoomOut} disabled={defaultZoom < 0.2} />
						</Tooltip>
						<Button>{Math.floor(defaultZoom * 10 * 10) + "%"}</Button>
						<Tooltip title="放大视图">
							<Button icon={<Icon icon="ep:zoom-in" />} onClick={processZoomIn} disabled={defaultZoom > 4} />
						</Tooltip>
						<Tooltip title="重置视图并居中">
							<Button icon={<Icon icon="ep:scale-to-original" />} onClick={processReZoom} />
						</Tooltip>
					</div>
					<div className="designerPanel-buttonGroup">
						<Button
							icon={<Icon icon="ep:plus" />}
							onClick={processSave}
							type={props.headerButtonType}
							// disabled={simulationStatus}
						>
							保存模型
						</Button>
					</div>
				</div>
			</div>
			<div className="my-process-designer__container">
				<div className="my-process-designer__canvas" id="bpmnCanvas" style={{ width: "1680px", height: "800px" }}></div>
			</div>
		</div>
	);
}
